// 编译： go build -ldflags "-H=windowsgui" .\clipboard.go
// windows的exe文件最好放在c:/windows/system32下
// 文件会生成在c:/windows目录下,程序会监控set-clipboard和get-clipboard两个文件。监控set-clipboard的写入并且扔到剪切板中
// 监控剪切板内容的变化并且写入get-clipboard

package main

import (
	"context"
	"fmt"
	"github.com/fsnotify/fsnotify"
	"github.com/sirupsen/logrus"
	"golang.design/x/clipboard"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"runtime"
)

func SetLogger() {
	logrus.SetFormatter(&logrus.JSONFormatter{
		FieldMap: logrus.FieldMap{
			logrus.FieldKeyFunc: "123",
			logrus.FieldKeyFile: "123",
		},
	})
	sysType := runtime.GOOS
	logFile := ""
	if sysType == "linux" {
		logFile = "/var/log/clipboard.log"
	} else {
		logFile = "clipboard.log"
	}

	file, err := os.OpenFile(logFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
	mw := io.MultiWriter(os.Stdout, file)
	if err != nil {
		panic(fmt.Sprintf("Log file %s not found", mw))
	}
	logrus.SetOutput(mw)
}

func main() {
	args := os.Args
	SetLogger()
	daemon := false
	for k, v := range args {
		if v == "-d" {
			daemon = true
			args[k] = ""
		}
	}
	if daemon {
		Daemonize(args...)
		return
	}
	setPasteFile := "C:\\Windows\\set-clipboard"
	_, err := os.Stat(setPasteFile)
	if err != nil {
		file, err := os.Create(setPasteFile)
		if err != nil {
			logrus.Error(err)
		} else {
			_ = file.Close()
		}

	}
	go getPaste()
	setPaste()
}

func Daemonize(args ...string) {
	var arg []string
	if len(args) > 1 {
		arg = args[1:]
	}
	logrus.Info("daemon start")
	cmd := exec.Command(args[0], arg...)
	cmd.Env = os.Environ()
	cmd.Start()
}

func getPaste() {
	//setPasteFile := "C:\\Windows\\set-clipboard"
	getPasteFile := "C:\\Windows\\get-clipboard"
	err := clipboard.Init()
	if err != nil {
		logrus.Error(err)
	}
	ch := clipboard.Watch(context.TODO(), clipboard.FmtText)
	for data := range ch {
		if data != nil {
			gf, err := os.Create(getPasteFile)
			defer func(gf *os.File) {
				err := gf.Close()
				if err != nil {

				}
			}(gf)
			if err != nil {
				logrus.Error(err)
				continue
			} else {
				_, err := gf.Write(data)
				if err != nil {
					logrus.Error(err)
					return
				}
			}
		}
	}
}

func setPaste() {
	setPasteFile := "C:\\Windows\\set-clipboard"
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		logrus.Error(err)
	}
	defer watcher.Close()
	done := make(chan bool)
	err = clipboard.Init()
	if err == nil {
		logrus.Error(err)
	}
	go func() {
		for {
			select {
			case event, ok := <-watcher.Events:
				if !ok {
					return
				}
				logrus.Info("event:", event)
				if event.Op&fsnotify.Write == fsnotify.Write {
					file, err := os.OpenFile(setPasteFile, os.O_RDWR, 0666)

					if err != nil {
						logrus.Error(err)
						continue
					}

					data, err := ioutil.ReadFile(setPasteFile)
					_ = file.Close()
					if err != nil {
						logrus.Error(err)
						continue
					} else {
						err := clipboard.Write(clipboard.FmtText, data)
						if err != nil {
							logrus.Error(err)
						}
					}
					continue
				}
			case err, ok := <-watcher.Errors:
				if !ok {
					return
				}
				logrus.Error("error:", err)
			}
		}
	}()
	err = watcher.Add(setPasteFile)
	if err != nil {
		logrus.Error(err)
	}
	<-done
}
